/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-08-23 16:24:02
 * @LastEditTime: 2021-08-26 10:45:10
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */
#include <string.h>
#include "ft_assert.h"
#include "cache.h"
#include "gmac.h"
#include "gmac_hw.h"
#include "gmac_dma.h"

#if defined(__aarch64__)
#include "kernel.h"

#define  GMAC_DMA_IS_64_BIT_MEMORY(addr)  (GENMASK_ULL(63, 32) & (uintptr)(addr))
#else
#define  GMAC_DMA_IS_64_BIT_MEMORY(addr)  (FALSE)
#endif

/**
 * @name: GmacDmaInitRxDescRing
 * @msg: init Rx DMA descriptor as ring structure
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 * @param {GmacDmaDesc} *pRxDescTbl
 * @param {u8} *pRxBuf
 * @param {u32} descPreBufLen
 * @param {u32} rxBufCnt
 */
u32 GmacDmaInitRxDescRing(GmacCtrl *pCtrl, GmacDmaDesc *pRxDescTbl, u8 *pRxBuf, u32 descPreBufLen, u32 rxBufCnt)
{
    FT_ASSERTZERONUM(pCtrl && pRxDescTbl && pRxBuf);
    u32 i;
    GmacDmaDesc *pCurRxDesc;

    if ((GMAC_DMA_IS_64_BIT_MEMORY(pRxDescTbl + rxBufCnt * sizeof(GmacDmaDesc))) || 
        (GMAC_DMA_IS_64_BIT_MEMORY(pRxBuf + rxBufCnt * descPreBufLen)))
    {
        GMAC_ERROR("invalid rx descriptor memory %p or rx dma buf memory %p", 
                  pRxDescTbl + rxBufCnt * sizeof(GmacDmaDesc),
                  pRxBuf + rxBufCnt * descPreBufLen);
        return GMAC_ERR_INVALID_DMA_MEM;
    }

    /* init rx dma ring data */
    memset(&pCtrl->rxRing, 0, sizeof(pCtrl->rxRing));
    pCtrl->rxRing.descMaxNum = rxBufCnt; /* total num of rx desc and rx buf */
    pCtrl->rxRing.descIdx = 0; /* idx of rx desc */
    pCtrl->rxRing.descBufIdx = 0; /* idx of rx buf */
    pCtrl->rxRing.descBufBase = pRxBuf; /* base addr of rx buf */

    memset(pRxDescTbl, 0, sizeof(GmacDmaDesc) * rxBufCnt);

    for (i = 0; i < rxBufCnt; i++)
    {
        pCurRxDesc = pRxDescTbl + i;
        pCurRxDesc->status = GMAC_DMA_RDES0_OWN;
        pCurRxDesc->ctrl   = (GMAC_DMA_RDES1_BUFFER1_SIZE_MASK & descPreBufLen);
        FCacheDCacheInvalidateRange((uintptr)&pRxBuf[i * descPreBufLen], descPreBufLen);
        pCurRxDesc->buf1Addr = (u32)((uintptr)&pRxBuf[i * descPreBufLen]);

        if ((rxBufCnt - 1) == i)
        {
            pCurRxDesc->ctrl |= GMAC_DMA_RDES1_END_RING;
        }
    }

    /* flush descriptor */
    pCtrl->rxDesc = pRxDescTbl;
    FCacheDCacheInvalidateRange((uintptr)pCtrl->rxDesc, sizeof(GmacDmaDesc) * rxBufCnt);

    GMAC_WRITE_REG(pCtrl, GMAC_DMA_RX_LIST_BASE_OFFSET, (u32)(uintptr)pRxDescTbl);
    return GMAC_SUCCESS;
}

/**
 * @name: GmacDmaInitTxDescRing
 * @msg: init Tx DMA descriptor as ring structure
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 * @param {GmacDmaDesc} *pTxDescTbl
 * @param {u8} *pTxBuf
 * @param {u32} descPreBufLen
 * @param {u32} txBufCnt
 */
u32 GmacDmaInitTxDescRing(GmacCtrl *pCtrl, GmacDmaDesc *pTxDescTbl, u8 *pTxBuf, u32 descPreBufLen, u32 txBufCnt)
{
    FT_ASSERTZERONUM(pCtrl && pTxDescTbl && pTxBuf);
    u32 i;
    GmacDmaDesc *pCurTxDesc;

    if ((GMAC_DMA_IS_64_BIT_MEMORY(pTxDescTbl + txBufCnt * sizeof(GmacDmaDesc))) || 
        (GMAC_DMA_IS_64_BIT_MEMORY(pTxBuf + txBufCnt * descPreBufLen)))
    {
        GMAC_ERROR("invalid tx descriptor memory %p or tx dma buf memory %p", 
                  pTxDescTbl + txBufCnt * sizeof(GmacDmaDesc),
                  pTxBuf + txBufCnt * descPreBufLen);
        return GMAC_ERR_INVALID_DMA_MEM;
    }

    memset(&pCtrl->txRing, 0, sizeof(pCtrl->txRing));
    pCtrl->txRing.descMaxNum = txBufCnt;
    pCtrl->txRing.descIdx = 0;
    pCtrl->txRing.descBufIdx = 0;
    pCtrl->txRing.descBufBase = pTxBuf;
    memset(pTxDescTbl, 0, sizeof(GmacDmaDesc) * txBufCnt);

    pTxDescTbl[txBufCnt - 1].ctrl |= GMAC_DMA_TDES1_END_RING;

    for (i = 0; i < txBufCnt; i++)
    {
        pCurTxDesc = pTxDescTbl + i;
        FCacheDCacheInvalidateRange((uintptr)&pTxBuf[i * descPreBufLen], descPreBufLen);
        pCurTxDesc->buf1Addr = (u32)((uintptr)&pTxBuf[i * descPreBufLen]);
        pCurTxDesc->status  = 0;
    }

    /* flush descriptor */
    pCtrl->txDesc = pTxDescTbl;
    FCacheDCacheInvalidateRange((uintptr)pCtrl->txDesc, txBufCnt * sizeof(GmacDmaDesc));

    GMAC_WRITE_REG(pCtrl, GMAC_DMA_TX_LIST_BASE_OFFSET, (u32)(uintptr)pTxDescTbl);
    return GMAC_SUCCESS;    
}

/**
 * @name: GmacDmaStart
 * @msg: enable Tx/Rx and start DMA
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 */
u32 GmacDmaStart(GmacCtrl *pCtrl)
{
    FT_ASSERTZERONUM(pCtrl);

    /* enable dma tx and rx */
    GMAC_SET_BIT(pCtrl, GMAC_DMA_OP_OFFSET, (GMAC_DMA_OP_SR | GMAC_DMA_OP_ST));

    /* enable gmac tx and rx */
    GMAC_SET_BIT(pCtrl, GMAC_CONF_OFFSET, (GMAC_CONF_RX_EN | GMAC_CONF_TX_EN));

    /* clear Tx and Rx process stopped flags */
    GMAC_WRITE_REG(pCtrl, GMAC_DMA_INTR_OFFSET, 
                  (GMAC_DMA_INTR_ENA_RIE | GMAC_DMA_INTR_ENA_AIE | GMAC_DMA_INTR_ENA_NIE));

    return GMAC_SUCCESS;
}

/**
 * @name: GmacDmaResumeRecv
 * @msg: start rx after setup DMA descriptor
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 */
u32 GmacDmaResumeRecv(GmacCtrl *pCtrl)
{
    FT_ASSERTZERONUM(pCtrl);

    if (GMAC_READ_REG(pCtrl, GMAC_DMA_STATUS_OFFSET) & GMAC_DMA_STATUS_RU)
    {
        GMAC_INFO("resume recv");
        /* Clear RBUS GMAC DMA flag */
        GMAC_W1C_BIT(pCtrl, GMAC_DMA_STATUS_OFFSET, GMAC_DMA_STATUS_RU);
        /* Resume DMA transmission*/
        GMAC_WRITE_REG(pCtrl, GMAC_DMA_RX_POLL_REQ_OFFSET, GMAC_POLL_DATA);
    }
    else
    {
        GMAC_WRITE_REG(pCtrl, GMAC_DMA_RX_POLL_REQ_OFFSET, GMAC_POLL_DATA);
    }

    return GMAC_SUCCESS;
}


/**
 * @name: GmacDmaResumeTran
 * @msg: start tx after setup DMA descriptor
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 */
u32 GmacDmaResumeTran(GmacCtrl *pCtrl)
{
    FT_ASSERTZERONUM(pCtrl);
    if (GMAC_READ_REG(pCtrl, GMAC_DMA_STATUS_OFFSET) & GMAC_DMA_STATUS_TU)
    {   
        GMAC_INFO("resume trans");
        /* Clear TBUS GMAC DMA flag */
        GMAC_W1C_BIT(pCtrl, GMAC_DMA_STATUS_OFFSET, GMAC_DMA_STATUS_TU);
        /* Resume DMA transmission */
        GMAC_WRITE_REG(pCtrl, GMAC_DMA_TX_POLL_REQ_OFFSET, GMAC_POLL_DATA);
    }
    else
    {
        GMAC_WRITE_REG(pCtrl, GMAC_DMA_TX_POLL_REQ_OFFSET, GMAC_POLL_DATA);
    }

    return GMAC_SUCCESS;
}

/**
 * @name: GmacDmaRxFrame
 * @msg: receive frame from RX DMA descirptor
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 */
u32 GmacDmaRxFrame(GmacCtrl *pCtrl)
{
    FT_ASSERTZERONUM(pCtrl);
    volatile GmacDmaDesc *pCurRxDesc = &pCtrl->rxDesc[pCtrl->rxRing.descIdx];
    u32 descCnt = 0;
    u32 flag = (GMAC_DMA_RDES0_FIRST_DESCRIPTOR | GMAC_DMA_RDES0_LAST_DESCRIPTOR);

    while ((0 == (GMAC_DMA_RDES0_OWN & pCurRxDesc->status)) && 
           (descCnt < pCtrl->rxRing.descMaxNum))
    {
        descCnt++;

        if (GMAC_DMA_RDES0_FIRST_DESCRIPTOR == (flag & pCurRxDesc->status))
        {
            pCtrl->rxRing.descBufIdx = pCtrl->rxRing.descIdx;
            GMAC_DMA_INC_DESC(pCtrl->rxRing.descIdx, pCtrl->rxRing.descMaxNum);
            pCurRxDesc = &pCtrl->rxDesc[pCtrl->rxRing.descIdx];
        }
        else if (0 == (flag & pCurRxDesc->status))
        {
            GMAC_DMA_INC_DESC(pCtrl->rxRing.descIdx, pCtrl->rxRing.descMaxNum);
            pCurRxDesc = &pCtrl->rxDesc[pCtrl->rxRing.descIdx];
        }
        else
        {
            pCtrl->rxRing.descBufIdx = pCtrl->rxRing.descIdx;
            GMAC_DMA_INC_DESC(pCtrl->rxRing.descIdx, pCtrl->rxRing.descMaxNum);
            return GMAC_SUCCESS;
        }
    }

    return GMAC_ERR_TRANS_FAILED;
}

/**
 * @name: GmacDmaTransFrame
 * @msg: transmit frame by TX DMA descriptor
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 * @param {u32} frameLen
 */
u32 GmacDmaTransFrame(GmacCtrl *pCtrl, u32 frameLen)
{
    FT_ASSERTZERONUM(pCtrl);
    u32 size = 0U;
    u32 i = 0U;
    u32 bufCnt = 0U;
    u32 ret = 0;
    volatile GmacDmaDesc *txDesc;

    if (0U == frameLen)
    {
        return GMAC_SUCCESS;
    }

    if (GMAC_MAX_PACKET_SIZE < frameLen)
    {
        bufCnt = frameLen / GMAC_MAX_PACKET_SIZE;
        if (frameLen % GMAC_MAX_PACKET_SIZE)
            bufCnt++;
    }
    else
    {
        bufCnt = 1U;
    }

    GMAC_DEBUG("framelen: %ld, trans buf cnt: %ld, desc idx: %ld",
              frameLen, bufCnt, pCtrl->txRing.descIdx);
   
    if (1U == bufCnt)
    {
        txDesc = &pCtrl->txDesc[pCtrl->txRing.descIdx];
        
        /* Set LAST and FIRST segment */
        txDesc->ctrl |= (GMAC_DMA_TDES1_FIRST_SEGMENT | GMAC_DMA_TDES1_LAST_SEGMENT);
        
        /* Set frame size */
        txDesc->ctrl &= ~(GMAC_DMA_TDES1_BUFFER1_SIZE_MASK);
        txDesc->ctrl |= (frameLen & GMAC_DMA_TDES1_BUFFER1_SIZE_MASK);

        /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
        txDesc->status |= GMAC_DMA_TDES0_OWN;
        GMAC_DMA_INC_DESC(pCtrl->txRing.descIdx, pCtrl->txRing.descMaxNum);
        
    }
    else
    {
        for (i = 0U; i < bufCnt; i++)
        {
            txDesc = &pCtrl->txDesc[pCtrl->txRing.descIdx];
            
            /* Clear FIRST and LAST segment bits */
            txDesc->ctrl &= ~(GMAC_DMA_TDES1_FIRST_SEGMENT | GMAC_DMA_TDES1_LAST_SEGMENT);

            if (0U == i)
            {
                txDesc->ctrl |= GMAC_DMA_TDES1_FIRST_SEGMENT; /* Setting the first segment bit */
            }

            /* Program size */
            txDesc->ctrl &= ~(GMAC_DMA_TDES1_BUFFER1_SIZE_MASK);
            txDesc->ctrl |= (GMAC_MAX_PACKET_SIZE & GMAC_DMA_TDES1_BUFFER1_SIZE_MASK);

            if ((bufCnt - 1) == i)
            {
                /* Setting the last segment bit */
                txDesc->ctrl |= GMAC_DMA_TDES1_LAST_SEGMENT;
                size = frameLen - (bufCnt - 1U) * GMAC_MAX_PACKET_SIZE;
                txDesc->ctrl &= ~(GMAC_DMA_TDES1_BUFFER1_SIZE_MASK);
                txDesc->ctrl |= (size & GMAC_DMA_TDES1_BUFFER1_SIZE_MASK);
            }
           
            /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
            txDesc->status |= GMAC_DMA_TDES0_OWN;
            GMAC_DMA_INC_DESC(pCtrl->txRing.descIdx, pCtrl->txRing.descMaxNum);
            
        }
    }

    ret = GmacDmaResumeTran(pCtrl);

    return ret;

}

/**
 * @name: GmacDmaResumeUnderflow
 * @msg: resume DMA transmit from under flow
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 */
void GmacDmaResumeUnderflow(GmacCtrl *pCtrl)
{
    FT_ASSERTVOID(pCtrl);
    u32 status;

    if (FT_COMPONENT_IS_READY != pCtrl->isReady)
        return;

    status = GMAC_READ_REG(pCtrl, GMAC_DMA_STATUS_OFFSET);
    if (GMAC_DMA_STATUS_UNF & status)
    {
        /* clear TBUS GMAC DMA flag */
        GMAC_W1C_BIT(pCtrl, GMAC_DMA_STATUS_OFFSET, GMAC_DMA_STATUS_UNF); 

        /* resume DMA transmission*/
        GMAC_WRITE_REG(pCtrl, GMAC_DMA_TX_POLL_REQ_OFFSET, GMAC_POLL_DATA);               
    }

    return;
}

#define GMAC_TRUE_FALSE_STR(x) ((x)?"TRUE":"FALSE")
/**
 * @name: GmacDmaProbe
 * @msg: probe gmac dma state
 * @return {*}
 * @param {GmacCtrl} *pCtrl
 * @param {boolean} rx
 */
void GmacDmaProbe(GmacCtrl *pCtrl, boolean rx)
{
    FT_ASSERTVOID(pCtrl);
    u32 bufIdx, regVal;
    u32 bufInc = 0;

    if (TRUE == rx)
    {
        GMAC_INFO("descriptor ring: cur idx: %ld, cur buf idx: %lx, size: %ld", 
                pCtrl->rxRing.descIdx, pCtrl->rxRing.descBufIdx, 
                pCtrl->rxRing.descMaxNum);

        regVal = GMAC_READ_REG(pCtrl, GMAC_DMA_RX_LIST_BASE_OFFSET);
        GMAC_INFO(" first rx desc addr: 0x%lx",
                (GMAC_DMA_RCV_BASE_ADDR_START_REC_LIST & regVal));
        regVal = GMAC_READ_REG(pCtrl, GMAC_DMA_HOST_RX_DESC_OFFSET);
        GMAC_INFO(" cur rx desc addr: 0x%lx", regVal);
        regVal = GMAC_READ_REG(pCtrl, GMAC_DMA_HOST_RX_BUF_ADDR_OFFSET);
        GMAC_INFO(" cur rx buff addr: 0x%lx", regVal);

        for (bufIdx = 0; bufIdx < pCtrl->rxRing.descMaxNum; bufIdx++)
        {
            GMAC_INFO("@%ld %ld - 0x%p", bufIdx, bufInc, &pCtrl->rxDesc[bufIdx]);
            GMAC_INFO(" status: 0x%lx", pCtrl->rxDesc[bufIdx].status);
            GMAC_INFO("     own by dma: %s", GMAC_TRUE_FALSE_STR(GMAC_DMA_RDES0_OWN & pCtrl->rxDesc[bufIdx].status));
            GMAC_INFO(" ctrl: 0x%lx", pCtrl->rxDesc[bufIdx].ctrl);
            GMAC_INFO("     rx buf size: %ld", 
                    (GMAC_DMA_RDES1_BUFFER1_SIZE_MASK & pCtrl->rxDesc[bufIdx].ctrl));        
            GMAC_INFO(" buf addr: 0x%lx", pCtrl->rxDesc[bufIdx].buf1Addr);
            GMAC_INFO(" reserved: 0x%lx", pCtrl->rxDesc[bufIdx].next);
            GMAC_DMA_INC_DESC(bufInc, pCtrl->rxRing.descMaxNum);
        }

        GMAC_INFO("dma desc info");
        GMAC_INFO(" rx desc: %p, size: %ld, cur idx: %ld", 
                pCtrl->rxRing, pCtrl->rxRing.descMaxNum, pCtrl->rxRing.descIdx); 
        GMAC_INFO(" rx buf: %p", pCtrl->rxRing.descBufBase);      
    }
    else
    {
        GMAC_INFO("descriptor ring: cur idx: %ld, cur buf idx: %ld, size: %ld, buf base: 0x%p",
                pCtrl->txRing.descIdx, pCtrl->txRing.descBufIdx, 
                pCtrl->txRing.descMaxNum, pCtrl->txRing.descBufBase); 

        regVal = GMAC_READ_REG(pCtrl, GMAC_DMA_TX_LIST_BASE_OFFSET);
        GMAC_INFO(" first tx desc addr: 0x%lx",
                (GMAC_DMA_TX_BASE_ADDR_START_TRA_LIST & regVal));
        regVal = GMAC_READ_REG(pCtrl, GMAC_DMA_HOST_TX_DESC_OFFSET);
        GMAC_INFO(" cur tx desc addr: 0x%lx", regVal);
        regVal = GMAC_READ_REG(pCtrl, GMAC_DMA_HOST_TX_BUF_ADDR_OFFSET);
        GMAC_INFO(" cur tx buff addr: 0x%lx", regVal);

        for (bufIdx = 0; bufIdx < pCtrl->txRing.descMaxNum; bufIdx++)
        {
            GMAC_INFO("@%ld %ld - 0x%p", bufIdx, bufInc, &pCtrl->txDesc[bufIdx]);
            GMAC_INFO(" status: 0x%lx", pCtrl->txDesc[bufIdx].status);
            GMAC_INFO("     own by dma: %s", GMAC_TRUE_FALSE_STR(GMAC_DMA_TDES0_OWN & pCtrl->txDesc[bufIdx].status));
            GMAC_INFO(" ctrl: 0x%lx", pCtrl->txDesc[bufIdx].ctrl);
            GMAC_INFO("     tx buf size: %ld", 
                    (GMAC_DMA_TDES1_BUFFER1_SIZE_MASK & pCtrl->txDesc[bufIdx].ctrl));        
            GMAC_INFO(" buf addr: 0x%lx", pCtrl->txDesc[bufIdx].buf1Addr);
            GMAC_INFO(" reserved: 0x%lx", pCtrl->txDesc[bufIdx].next);
            GMAC_DMA_INC_DESC(bufInc, pCtrl->txRing.descMaxNum);    
        } 

        GMAC_INFO("dma desc info");
        GMAC_INFO("descriptor ring: cur idx: %ld, cur buf idx: %ld, size: %ld, buf base: 0x%p",
                pCtrl->txRing.descIdx, pCtrl->txRing.descBufIdx, 
                pCtrl->txRing.descMaxNum, pCtrl->txRing.descBufBase); 
    }

    (void)regVal;
    return;
}


u32 GmacRingGetReceivedFrameIT(GmacCtrl *Gmac)
{
    u32 DescriptorsCounter = 0U;
    volatile GmacDmaDesc *RxDesc;
    RxDesc = &Gmac->rxDesc[Gmac->rxRing.descIdx];

    while (((RxDesc->status & GMAC_DMA_RDES0_OWN) == 0) && DescriptorsCounter < Gmac->rxRing.descMaxNum)
    {
        DescriptorsCounter++;

        /* Check if first segment in frame */
        if ((RxDesc->status & (GMAC_DMA_RDES0_FIRST_DESCRIPTOR | GMAC_DMA_RDES0_LAST_DESCRIPTOR)) == (u32)GMAC_DMA_RDES0_FIRST_DESCRIPTOR)
        {
            Gmac->rxRing.descBufIdx = Gmac->rxRing.descIdx;
            /* Point to next descriptor */
            GMAC_DMA_INC_DESC(Gmac->rxRing.descIdx, Gmac->rxRing.descMaxNum);
            RxDesc = &Gmac->rxDesc[Gmac->rxRing.descIdx];
        } /* Check if intermediate segment */
        else if ((RxDesc->status & (GMAC_DMA_RDES0_FIRST_DESCRIPTOR | GMAC_DMA_RDES0_LAST_DESCRIPTOR)) == 0)
        {
            
            /* Point to next descriptor */
            GMAC_DMA_INC_DESC(Gmac->rxRing.descIdx, Gmac->rxRing.descMaxNum);
            RxDesc = &Gmac->rxDesc[Gmac->rxRing.descIdx];
        } /* Should be last segment */
        else
        {
            Gmac->rxRing.descBufIdx = Gmac->rxRing.descIdx;
            GMAC_DMA_INC_DESC(Gmac->rxRing.descIdx, Gmac->rxRing.descMaxNum);
            return GMAC_SUCCESS;
        }
    }
    
    return GMAC_ERR_TRANS_FAILED;
}
